#include "dynamicmap.h"
#include "dplink.h"
#include "protocolparse.h"
#include "viewobject.h"
#include "common.h"
#include <QSurfaceFormat>
#ifdef __linux__
#include <sys/wait.h>
#endif

DynamicMap *DynamicMap::map_obj = NULL;

#ifdef __cplusplus
extern "C" {
#endif

const char* _SOCKNAME = "/tmp/dpsock";

DynamicRunParam::DynamicRunParam()
{
    ip                  = 0;
    port                = 0;               /// 端口
    tcp_ip              = 0;
    tcp_port            = 0;
    memset(inter_addr, 0, sizeof(inter_addr));
//    memset(xml_path, 0, sizeof(xml_path));
//    memset(img_path, 0, sizeof(img_path));
    res_path = "";
}

DynamicMap::DynamicMap()
{
    local_ip = 0;
    local_port = 0;
    linker = NULL;
    parse = NULL;
//    memset(img_path, 0, sizeof (img_path));
//    memset(xml_path, 0, sizeof (xml_path));
    m_res_path = "";
    ptr_protocol_data = NULL;
}

DynamicMap *DynamicMap::get_map()
{
    if (map_obj == NULL)
        map_obj = new DynamicMap;
    return map_obj;
}

void DynamicMap::kill_old_mvc_python_proc()
{
    LOG_PRINTF("kill_old_mvc_python_proc\n");
    FILE *fp = popen("ps | grep mvc.py | awk '{print $1}'", "r");
    char buff[100];
    if (fgets(buff, 100, fp))
    {
        LOG_PRINTF("popen get pid: %s\n", buff);
        char cmd[120];
        sprintf(cmd, "kill %s", buff);
        LOG_PRINTF("kill mvc.py process cmd: %s\n", cmd);
        system(cmd);
    }
}

void DynamicMap::init(QString path)
{
    //初始化参数
    DynamicRunParam param;

    //for udp
    param.ip = INADDR_ANY;//inet_addr(ip_buff)
    param.port = 12366;

    param.res_path = path + RES;

    char python_path[100];
    memset(python_path, 0, sizeof(python_path));

    QByteArray ba = path.toLatin1();

    snprintf(python_path, sizeof(python_path), "%s%s", ba.data(), "/res/mvc.py");
    LOG_PRINTF("python path:%s\n", python_path);
     if (!g_run_python)
     {
         LOG_PRINTF("run dynamicMap without python\n");
         int ret = create_obj(param);
         if (ret < 0)
         {
              LOG_PRINTF("create obj error:%d\n", errno);
              return;
         }
     }
     else
     {
         int ret = create_obj(param);
         if (ret < 0)
         {
              LOG_PRINTF("create obj error:%d\n", errno);
              return;
         }

         kill_old_mvc_python_proc();

         pid_t  pid = fork();
         if (pid < 0)
         {
             LOG_PRINTF("fork failed!\n");
         }
         else if (pid == 0) //child
         {
             LOG_PRINTF("child %d success of fork!\n", getpid());
             int ret = execl("/app/python/bin/python3","/app/python/bin/python3", python_path, "12366", NULL);
             LOG_PRINTF("execl run python ret:%d\n", ret);
             exit(0);
         }
         else
         {
             waitpid(pid, 0, WNOHANG);
             LOG_PRINTF("parent %d success of fork, run continue \n", getpid());
         }
     }
}

int DynamicMap::create_obj(DynamicRunParam &svr_param)
{
   int ret = 0;

   try
   {
       linker          = new DPSockLink;
       parse           = new ProtocolParse;
   }
   catch (...)
   {
       ret = -ENOMEM;
       return ret;
   }

   DMapParam  param;
   memset(&param, 0, sizeof(param));
   param.svr_addr              = svr_param.ip;
   param.svr_port              = htons(svr_param.port);
   param.svr_data_cb           = link_svr_data_cb;
   param.svr_data_cb_ctx       = this;

   param.tcp_svr_addr          = svr_param.tcp_ip;
   param.tcp_svr_port          = htons(svr_param.tcp_port);
   param.tcp_svr_data_cb       = tcp_link_svr_data_cb;
   param.tcp_svr_data_cb_ctx    = this;

   /// unix
   snprintf(param.inter_msg_addr, sizeof(param.inter_msg_addr), "%s", svr_param.inter_addr);      /// unix param
   param.inter_msg_cb          = link_inter_msg_cb;
   param.inter_msg_cb_ctx      = this;

   /// 触发器
   param.event_trigger_cb      = link_trigger_cb;                                              /// period trigger
   param.ev_trigger_ctx        = this;

   set_event_cb();

   ret = linker->create(param);

   parse->set_protocol(linker->get_protocol());

   init_param(svr_param);

   ret = parse->create(get_res_path());
   if (0 != ret)
   {
      return -ENOMEM;
   }

   return ret;

}

void DynamicMap::init_param(DynamicRunParam &param)
{
    if (linker->get_protocol() == IPPROTO_UDP)
    {
        local_ip = param.ip;
        local_port = param.port;
    }

    if (linker->get_protocol() == IPPROTO_TCP)
    {
        local_ip = param.tcp_ip;
        local_port = param.tcp_port;
    }

//    snprintf(img_path, sizeof (img_path), "%s", param.img_path);
//    snprintf(xml_path, sizeof (xml_path), "%s", param.xml_path);

    m_res_path = param.res_path;

}

void DynamicMap::set_event_cb()
{
    if (NULL != parse)
    {
        parse->set_send_data_cb(link_buf_send, this);

        //解析完协议之后的回调函数
        parse->set_parse_file_cb(notify_to_window, this);
    }
}

void DynamicMap::notify_to_window(void *context, QString file)
{
     DynamicMap *map = static_cast<DynamicMap*>(context);
     map->signal_update_file(file, map->ptr_protocol_data);
}

int DynamicMap::link_buf_send(void *context, void *link_context, void *buf, int len, uint32_t ip, uint16_t port, uint64_t time)
{
    (void)(time);
    DynamicMap *map = static_cast<DynamicMap *>(context);
    return map->linker->buf_send_data(link_context, buf, len, ip, port);
}

/// 链路数据回调函数
void DynamicMap::link_svr_data_cb(void *context, void *buf, int buf_len, uint32_t rmt_ip, uint16_t rmt_port, uint64_t time)
{
    (void)(time);
    (void)(rmt_ip);
    (void)(rmt_port);
    DynamicMap *map = static_cast<DynamicMap *>(context);
    if (!map)
        return;
    if (map->ptr_protocol_data == NULL)
    {
       map->ptr_protocol_data = new ProtocolData;
    }

    map->ptr_protocol_data->reset();
//  map->parse->data_in(buf, buf_len, rmt_ip, rmt_port, time);

    //获取udp数据之后传输给parse进行解析，进行解析再根据notify_to_window回调函数显示
    map->parse->data_in_from_unix(buf, buf_len, time, map->ptr_protocol_data);
}

/// 链路数据tcp回调函数
int DynamicMap::tcp_link_svr_data_cb(void *context, void *buf, int buf_len, uint32_t rmt_ip, uint16_t rmt_port, uint64_t time)
{
    (void)(time);
    DynamicMap *map = static_cast<DynamicMap *>(context);
    map->parse->data_in(buf, buf_len, rmt_ip, rmt_port, time);
    return 0;
}

/// link inter msg data callback
void DynamicMap::link_inter_msg_cb(void *context, void *buf, int buf_len, char *rmt_addr, uint64_t time)
{
    (void) (rmt_addr);
    DynamicMap *map = static_cast<DynamicMap *>(context);
    if (!map)
        return;
    if (map->ptr_protocol_data == NULL)
    {
       map->ptr_protocol_data = new ProtocolData;
    }

    map->ptr_protocol_data->reset();

    map->parse->data_in_from_unix(buf, buf_len, time, map->ptr_protocol_data);
    return;
}

void DynamicMap::link_trigger_cb(void *context, uint64_t cur_time)
{
    (void)context;
    (void)cur_time;
//    schedule();// keepalive
    return;
}

#ifdef __cplusplus
}
#endif
